computersfandomcom_he-20200214-history
שפת C/פלט וקלט קבצים
בפרק פלט וקלט ראינו כיצד לפלוט ולקלוט מידע מהמשתמש ישירות. בפרק זה נראה כיצד לפלוט ולקלוט מידע מ''קבצים''. }} תו סיום-הקובץ EOF במחרוזות ותו האפס, ראינו שיש מוסכמה לפיה תו האפס מסיים את חלק המחרוזת המכיל תוכן אמיתי (גם אם המערך ארוך יותר). באופן דומה, ישנו תו מיוחד, EOF, המסמן לפי מוסכמה את סיום התוכן האמיתי של קובץ. המבנה FILE והעבודה אתו המבנה FILE מוגדר ב , והוא משמש לכל פונקציות הפלט והקלט שנראה בפרק זה. כמו לכל מבנה אחר, גם למבנה FILE יש שדות, אולם כלל לא נאזכר כאן מהם שדותיו ומשמעותם, שכן המבנה לא תוכנן כך שייגשו ישירות לשדותיו. צורת העבודה עם מבנה זה היא כזו: #משתמשים בפונקציית ספריה כדי לקבל מצביע למבנה זה. נראה זאת בפתיחת קובץ. #משתמשים בפונקציות הספריה כדי לבצע פעולות שונות בקובץ. אחד הארגומנטים שמקבלת כל פונקציה היא מצביע לFILE, ומעבירים לפונקציה את המצביע שקבלנו. #בסיום השימוש בקובץ, משתמשים בפונקציית ספרייה כדי להודיע שסיימנו להשתמש בו, וגם כאן מעבירים לפונקציה את המצביע שקיבלנו. נראה זאת בסגירת קובץ. פתיחת קובץ הקריאה לfopen והערך המוחזר פתיחת קובץ מתבצעת על ידי קריאה לfopen, המחזיר מצביע לFILE. אם המצביע הנו NULL, פתיחת הקובץ נכשלה. לכן תמיד יש לבדוק את הערך המוחזר מפונקציה זו (הדבר דומה להקצאת זיכרון במידה מסויימת). כדי לפתוח את הקובץ "try.txt", לדוגמה, אפשר לבצע זאת: FILE *f = fopen("try.txt" , "rt"); if(!f) { /* Handle case where couldn't open file. */ } השורה הראשונה פותחת את הקובץ על ידי fopen, ומשימה את המצביע המוחזר למצביע f. הארגומנט הראשון שמקבלת הפונקציה הוא שם הקובץ (אם אינו בתיקית התוכנית, בנתיב מלא או יחסי אליו); הארגומנט השני הוא מחרוזת סוג הפתיחה, שעליה נדבר מיד, והיא כאן מבקשת לפתוח לקריאה קובץ טקסט (מלל). השורה הבאה בודקת למעשה אם f קיבל את הערך NULL. אם כן, פתיחת הקובץ נכשלה, ויש לטפל בכך. מחרוזת סוג הפתיחה בדוגמה שראינו זה עתה, מחרוזת סוג הפתיחה "rt" מבקשת לפתוח לקריאה קובץ טקסט (מלל): "r" מסמנת את מוד הפתיחה, המציינת מה רוצים לעשות עם הקובץ, ו"t" מסמנת את תוכן הקובץ. תמיד יוצרים את מחרוזת סוג הפתיחה על ידי בחירה של אחת מהאפשרויות בטבלה מוד הפתיחה שלאחריה בחירה של אחת מהאפשרויות בטבלה תוכן הקובץ. סגירת קובץ בסיום עבודה עם קובץ פתוח, יש לסגור אותו. הדבר דומה לשחרור זיכרון במידה מסויימת. הפונקציה fclose הפונקציה fclose סוגרת קובץ שנפתח על ידי fopen. משתמשים בה בצורה: fclose(); כאשר f הוא מצביע לFILE שהוחזר מקריאה מוצלחת מfopen. חשיבות סגירת קבצים קבצים פתוחים הם אחד ממשאבי מערכת ההפעלה, ולכן עדיף להמנע מלנהוג בהם בבזבוז. בפרט, יש לסגור כל קובץ שאותו פתחנו. פלט הפונקציה fprintf הפונקציה fprintf דומה מאד לפונקציה printf (שכבר ראינו בפלט וקלט): fprintf(f, "This line will be written to the file.\n"); יש לשים לב לשינויים הבאים: *הארגומנט הראשון הוא מצביע לFILE. *הפונקציה מדפיסה לקובץ שאותו מתאר הFILE. *רצוי לבדוק את הערך המוחזר מהפונקציה, שכן כתיבה לקובץ עלולה להיכשל. הפונקציה מחזירה מספר שלילי במקרה כישלון פלט. להלן דוגמה לבדיקה: if( fprintf("Hello world") < 0) ... /* Handle error. */ להלן דוגמה לשימוש בfprintf: #include int main() { FILE *const f = fopen("new_file.txt", "wt"); if(!f) { printf("Error: could not open file!\n"); return -1; } fprintf(f, "This line will be written to the file.\n"); fprintf(f, "Here is another line: %d + %d = %d", 2, 2, 2 + 2); fclose(f); return 0; } השורות: FILE *const f = fopen("new_file.txt", "wt"); if( !f ) { printf("Error: could not open file!\n"); return -1; } מייצרות קובץ בשם "new_file.txt", ופותחות אותו לכתיבה כקובץ טקסט, בודקות האם הפעולה הצליחה, ומטפלות במצב אם לא. השורות: fprintf(f, "This line will be written to the file.\n"); fprintf(f, "Here is another line: %d + %d = %d", 2, 2, 2 + 2); מראות קריאות דומות לאלה שהיינו עושים כדי להדפיס בעזרת printf, אלא שאנו משתמשים בfprintf, והארגומנט הראשון הוא המצביע לFILE. השורות: fclose(f); return 0; } סוגרות את הקובץ, ומודיעות למערכת ההפעלה שהתוכנית הצליחה. אם נריץ את התוכנית, נוכל לראות שאכן נוצר קובץ בשם המבוקש, ומופיעה בו השורה שכתבנו. עוד פונקציות הספריה הסטנדרטית כוללת עוד פונקציות פלט לקבצים, לדוגמה fputs וfwrite. קלט הפונקציה fscanf הפונקציה fscanf דומה מאד לפונקציה scanf (שכבר ראינו בפלט וקלט): fscanf(f, "%d", &count); יש לשים לב למעט השינויים הבאים: *הארגומנט הראשון הוא מצביע לFILE. *הפונקציה קולטת מהקובץ שאותו מתאר הFILE. *חשוב במיוחד לבדוק את הערכים המוחזרים מהקריאות, מפני שאין להניח את הצלחתן של קריאות מקובץ. נניח שfscanf ביקשה לקרוא ל משתנים. אז הקריאה מוצלחת אם הפונקציה מחזירה n. להלן דוגמה לבדיקה: int d; char c; if( fscanf("%d %c", &d, &c) != 2) ... /* Handle error. */ הפונקציה fgets הפונקציה fgets מאפשרת לקלוט מחרוזת מקובץ לתוך מערך תווים, כפי שראינו בקלט מחרוזות. לדוגמה: char a50; fgets(a, 49, f); הקריאה: fgets(a, 49, stdin); תקלוט עד 49 תווים מתוך קובץ. אם ב49 התווים הראשונים יש מעבר לשורה חדשה (על ידי Enter), ייקלטו רק התווים עד שם. הארגומנט השלישי, f, הוא מצביע לFILE שממנו יקראו התווים. עוד פונקציות הספריה הסטנדרטית כוללת עוד פונקציות קלט מקבצים, לדוגמה fread. זרמים סטנדרטיים הספריה הסטנדרטית מגדירה שלושה מצביעים ל"קבצים" שלמעשה אינם לרוב קבצים אמיתיים, אלא צורות תקשורת עם המשתמש: *stdin הוא מצביע ל"קובץ" שהוא למעשה המקלדת. *stdout הוא מצביע ל"קובץ" שהוא למעש המסך. *stderr הוא מצביע ל"קובץ" שהוא למעשה גם כן המסך, אלא שהוא משמש לפלט שגיאות. אפשר להשתמש במצביעים אלה בפונקציות פלט הקבצים ובפונקציות קלט הקבצים. לדוגמה, היינו יכולים לכתוב את שלום עולם! כך: #include int main() { fprintf(stdout, "Hello world\n"); return 0; } שינוי ומציאת המיקום בקובץ כשאנו כותבים לקובץ וקוראים ממנו, אין מניעה (לרוב) לחזור אחורה או לדלג קדימה. ולהמשיך את הקריאות והכתיבות ממקום אחר. בנושא זה נראה כיצד לעשות זאת. הפונקציה fseek זזים ממקום למקום, על ידי fseek, בצורה הזאת: fseek(, , ); כאשר: *f הוא מצביע לFILE. *offset הוא מספר הבתים שיש לזוז (מספר זה יכול להיות גם שלילי). *origin הוא מוצא התזוזה, והוא יכול להיות אחת משלוש האפשרויות הבאות: ** SEEK_CUR - המיקום הנוכחי ** SEEK_SET - תחילת הקובץ ** SEEK_END - סוף הקובץ לדוגמה: fseek( file, 2L, SEEK_CUR ); יזיז את המיקום 2 בתים קדימה מהמיקום הנוכחי. הפעולה הבאה שנעשה (קריאה או כתיבה) תתבצע במיקום החדש. הפונקציה ftell הפונקציה הנוכחית מחזירה את המיקום הנוכחי. קטע הקוד הבא מראה דוגמה לקריאה לפונקציה: long pos = ftell( file ); לאחר קריאה זו, pos יכיל את מספר הבתים מתחילת הקובץ ועד המיקום הנוכחי. פונקציה זו שימושית בעיקר בשילוב עם fseek. שומרים את המיקום הנוכחי, מבצעים פעולות קריאה וכתיבה כלשהן, וחוזרים למקום הנוכחי בעזרת fseek. קבצים